import * as cc from 'cc';
import NodeUtils from '../../../utils/NodeUtils';
import { ViewCtrlBase } from '../../../view/ViewCtrlBase';
import { ListViewDir } from './ListView';
import ListViewItemBase from './ListViewItemBase';
import PageViewPoint from './PageViewIndicator';

export interface PageViewParams {
    /**数据源 */
    arr_data: any[],
    /**控制器 */
    vc: ViewCtrlBase,
    /**是否清空重新创建 */
    is_clean?: boolean,
    /**创建间隔 */
    interval?: number,
    /**创建节点的起始索引 */
    from_index?: number,
    /**翻页结束事件 */
    on_page_turn?: (curIdx: number) => void,
}
const { ccclass, property, menu } = cc._decorator;
@ccclass("PageView")
@menu("扩展组件/PageView")
export default class PageView extends cc.Component {

    @property({ type: PageViewPoint, tooltip: "页标签" })
    indicator: PageViewPoint = null;

    /**列表选项 */
    @property({ type: cc.Prefab, tooltip: "列表选项预制体", displayName: "列表选项预制体" })
    itemPrefab: cc.Prefab = null;

    /**列表选项类组件类 */
    @property({ tooltip: "列表选项类组件类,必须继承自ListViewItemBase", displayName: "列表选项类组件类名" })
    itemClassName: string = "";

    @property({ tooltip: "列表选项锚点,默认中心0.5,上下:anchorY,左右:anchorX", displayName: "列表选项锚点" })
    itemAnchor: number = 0.5;

    @property({ type: cc.Enum(ListViewDir), tooltip: "列表添加方向", displayName: "列表添加方向" })
    direction: ListViewDir = ListViewDir.LEFT_TO_RIGHT;

    /**列表滚动容器 */
    @property({ type: cc.PageView, tooltip: "列表容器" })
    pageView: cc.PageView = null;


    /**列表项实例数量 */
    private _spawnCount: number = 3;
    /**列表项总数 */
    public _totalCount: number = 0;
    /**scrollView的内容容器 */
    private _content: cc.Node = null;
    /**视窗的大小 */
    public viewSize: cc.Size = null;
    /**存放列表项实例的数组 */
    private _items: Array<cc.Node> = [];
    /**列表项数据 */
    private _itemDataList: any[] = [];
    private vc: ViewCtrlBase;

    private _viewUITrans: cc.UITransform = null;
    private _maskUITrans: cc.UITransform = null;
    private _contentUITrans: cc.UITransform = null;

    private _onPageTurnCallback: (curIdx: number) => void = null;

    get curPageIdx(): number { return this.pageView.curPageIdx }
    onLoad() {
        //初始化
        this._onPageTurnCallback = null;
        this._viewUITrans = this.pageView.node.getComponent(cc.UITransform);
        this._content = this.pageView.content;
        this._contentUITrans = this._content.getComponent(cc.UITransform);
        this._maskUITrans = this._content.parent.getComponent(cc.UITransform);
        this.viewSize = this._viewUITrans.contentSize;
        this._items = [];

        let layoutContent = this._content.getComponent(cc.Layout) || this._content.getComponent(cc.Layout)

        switch (this.direction) {
            case ListViewDir.LEFT_TO_RIGHT:
                this._maskUITrans.anchorX = 0;
                this._contentUITrans.anchorX = 0;
                this.pageView.direction = cc.PageView.Direction.Horizontal;
                layoutContent.horizontalDirection = cc.Layout.HorizontalDirection.LEFT_TO_RIGHT;
                break;
            case ListViewDir.RIGHT_TO_LEFT:
                this._maskUITrans.anchorX = 1;
                this._contentUITrans.anchorX = 1;
                this.pageView.direction = cc.PageView.Direction.Horizontal;
                layoutContent.horizontalDirection = cc.Layout.HorizontalDirection.RIGHT_TO_LEFT;

                break;
            case ListViewDir.TOP_TO_BOTTOM:
                this._maskUITrans.anchorY = 1;
                this._contentUITrans.anchorY = 1;
                this.pageView.direction = cc.PageView.Direction.Vertical;
                layoutContent.verticalDirection = cc.Layout.VerticalDirection.TOP_TO_BOTTOM;

                break;
            case ListViewDir.BOTTOM_TO_TOP:
                this._maskUITrans.anchorY = 0;
                this._contentUITrans.anchorY = 0;
                this.pageView.direction = cc.PageView.Direction.Vertical;
                layoutContent.verticalDirection = cc.Layout.VerticalDirection.BOTTOM_TO_TOP;
                break;
        }
        this._content.setPosition(0, 0, 0);

        this._maskUITrans.anchorPoint = this._contentUITrans.anchorPoint.clone();
        this._content.removeAllChildren();
        // 暂停滚动
        this.enabled = false;
        this.pageView.enabled = false;

        this.pageView.node.on('page-turning', this.onPageTurn, this);
    }

    protected onDestroy(): void {
        this._onPageTurnCallback = null;
    }

    /**
     * 设置item的数据
     * @example
     *   setData([{id:1,msg:"a"},{id:2,msg:"b"}])
     * @param itemDataList item数据列表
     * @param vc 控制器
     * @param isClean 是否清除原本,重新创建
     * @param interval 异步创建间隔/秒
     */
    public async reloadData(params: PageViewParams) {
        this.vc = params.vc;
        //复制item数据，如果item数据源改变，则需要重新setData一次来显示新数据
        this._itemDataList = params.arr_data.slice();
        this._totalCount = this._itemDataList.length;

        if (params.on_page_turn) {
            this._onPageTurnCallback = params.on_page_turn;
        }
        // 暂停滚动
        this.enabled = false;
        this.pageView.enabled = false;
        await this.createItem(params);
        if (!this.node || !this.node.isValid) {
            return;
        }
        //运行滚动
        this.enabled = true;
        this.pageView.enabled = true;
        this.scrollToPage(params.from_index || 0, 0);
        this._onPageTurnCallback && this._onPageTurnCallback(this.pageView.getCurrentPageIndex());

        this.indicator && this.indicator.setPageView(this);
    }

    /**创建item实例 */
    private async createItem(params: PageViewParams) {
        this._calcContentSize();
        if (params.is_clean !== false) {
            this.clearAllItem();
            this.pageView.removeAllPages();
            for (let i = 0; i < this._totalCount; i++) {
                let pageName = `page_${i}`;
                let pageNode = this._content.getChildByName(pageName);
                if (!pageNode) {
                    pageNode = new cc.Node(`page_${i}`);
                    let pageUiTrans = pageNode.addComponent(cc.UITransform);
                    pageUiTrans.setContentSize(this.viewSize.clone());
                    this.pageView.addPage(pageNode)
                }
            }
            let len = this._totalCount < this._spawnCount ? this._totalCount : this._spawnCount;
            let startIdx = 0

            if (params.from_index != undefined) {
                //从指定索引开始创建
                startIdx = Math.max(Math.min(this._totalCount - len, params.from_index - 1), 0);
                let fromPosIdx = params.from_index;
                let maxFromIdx = this._totalCount - this._spawnCount + 1;
                if (maxFromIdx < params.from_index) {
                    fromPosIdx = maxFromIdx;
                }
                let contentPos = this._getContentPosByItemIdx(fromPosIdx)
                this._content.setPosition(contentPos)
            }

            let arrDataTemp = [];
            for (let i = 0; i < len; i++) { // spawn items, we only need to do this once
                const data = this._itemDataList[i + startIdx]
                if (!!data) {
                    arrDataTemp[i] = data;
                }
            }

            return NodeUtils.genNodeWithPrefabAndData(arrDataTemp, this.itemPrefab, params.interval || 0, (item: cc.Node, data: any, idx: number) => {
                const itemIdx = idx + startIdx;
                // const posInContent = this.getItemPosByItemIdx(itemIdx);
                // item.setPosition(posInContent);
                item.setPosition(0, 0, 0);
                if (this.itemClassName) {
                    const com: ListViewItemBase = (item.getComponent(this.itemClassName) || item.addComponent(this.itemClassName)) as ListViewItemBase;
                    com.setDelegage(this.vc)
                    com.updateItem(itemIdx, data, this._totalCount);
                }
                item.setParent(this.pageView.getPages()[itemIdx]);
                this._items.push(item);

            }, this)
        } else {
            for (let i = 0; i < this._items.length; i++) {
                const item = this._items[i];
                if (this.itemClassName) {
                    const com: ListViewItemBase = (item.getComponent(this.itemClassName) || item.addComponent(this.itemClassName)) as ListViewItemBase;
                    const data = this._itemDataList[com.itemIdx]
                    com.setDelegage(this.vc)
                    com.updateItem(com.itemIdx, data, this._totalCount);
                }
            }
        }

    }


    onPageTurn(pageView: cc.PageView) {
        // 回调的参数是 pageView 组件
        // 另外，注意这种方式注册的事件，也无法传递 customEventData
        let curIdx = pageView.getCurrentPageIndex();
        let items = this._items;
        for (let i = 0; i < items.length; ++i) {
            let nodeItem = items[i];
            let itemIdx = curIdx - 1 + i;
            if (itemIdx < 0 || itemIdx >= this._totalCount) {
                continue;
            }
            let pageItem = this.pageView.getPages()[itemIdx];
            if (this.itemClassName) {
                let comItem: ListViewItemBase = nodeItem.getComponent(this.itemClassName) as ListViewItemBase;
                if (this._itemDataList[itemIdx]) {
                    comItem.updateItem(itemIdx, this._itemDataList[itemIdx], this._itemDataList.length);
                }
            }
            if (pageItem) {
                nodeItem.removeFromParent();
                nodeItem.setParent(pageItem);
            }
        }
        this._onPageTurnCallback && this._onPageTurnCallback(curIdx);
        this.indicator && this.indicator.updateState();
    }

    /**
     * @desc 计算滑动容器的size
     */
    private _calcContentSize() {
        if (this.pageView.vertical) {
            this._contentUITrans.height = this._totalCount * this.viewSize.height;
        } else {
            this._contentUITrans.width = this._totalCount * this.viewSize.width;
        }
    }

    /**
     * @desc 根据item索引计算item坐标
     * @param itemIdx item索引
     * @returns 
     */
    public getItemPosByItemIdx(itemIdx: number) {
        switch (this.direction) {
            case ListViewDir.BOTTOM_TO_TOP:
                return cc.v3(0, this.viewSize.height * (this.itemAnchor + itemIdx));
            case ListViewDir.TOP_TO_BOTTOM:
                return cc.v3(0, this.viewSize.height * (this.itemAnchor + itemIdx));
            case ListViewDir.LEFT_TO_RIGHT:
                return cc.v3(this.viewSize.width * (this.itemAnchor + itemIdx), 0);
            case ListViewDir.RIGHT_TO_LEFT:
                return cc.v3(this.viewSize.width * (this.itemAnchor + itemIdx), 0);
        }
    }

    /**
     * @desc 根据世界坐标计算item索引
     * @param itemIdx item索引
     * @returns 
     */
    public getItemIdxByItemPos(worldPos: cc.Vec3) {
        let viewPos = this._contentUITrans.convertToNodeSpaceAR(worldPos);
        switch (this.direction) {
            case ListViewDir.BOTTOM_TO_TOP:
                return Math.floor((viewPos.y - this.viewSize.height * this.itemAnchor) / (this.viewSize.height))
            case ListViewDir.TOP_TO_BOTTOM:
                return Math.floor((viewPos.y + this.viewSize.height * this.itemAnchor) / (this.viewSize.height))
            case ListViewDir.LEFT_TO_RIGHT:
                return Math.floor((viewPos.x - this.viewSize.width * this.itemAnchor) / (this.viewSize.width))
            case ListViewDir.RIGHT_TO_LEFT:
                return Math.floor((viewPos.x + this.viewSize.width * this.itemAnchor) / (this.viewSize.width))
        }
    }

    private _getContentPosByItemIdx(itemIdx: number) {
        let offsetY = Math.max(Math.min(this.viewSize.height * itemIdx + this.viewSize.height * this.itemAnchor, this._contentUITrans.height - this._viewUITrans.height), 0)
        let offsetX = Math.max(Math.min(this.viewSize.width * itemIdx, this._contentUITrans.width - this._viewUITrans.width), 0)
        switch (this.direction) {
            case ListViewDir.BOTTOM_TO_TOP:
                return cc.v3(this._content.position.x, -offsetY);
            case ListViewDir.TOP_TO_BOTTOM:
                return cc.v3(this._content.position.x, offsetY);
            case ListViewDir.LEFT_TO_RIGHT:
                return cc.v3(-offsetX, this._content.position.y);
            case ListViewDir.RIGHT_TO_LEFT:
                return cc.v3(offsetX, this._content.position.x);
        }
    }
    /**
     * @desc 获取当前创建的实例集合
     */
    public getCurItems(): cc.Node[] {
        return this._items;
    }

    /**清理item实例 */
    private clearAllItem() {
        for (let i = 0, len = this._items.length; i < len; i++) {
            let item = this._items[i];
            item.destroy();
        }
        this._items.length = 0;

    }

    /**增加视图索引,可传负数 */
    public addPageIndex(count: number) {
        let curIdx = this.pageView.getCurrentPageIndex();

        let targetIdx = curIdx + count
        if (targetIdx >= this._totalCount) {
            targetIdx = 0;
            return;
        }
        if (targetIdx < 0) {
            targetIdx = this._totalCount - 1;
            return;
        }
        this.scrollToPage(targetIdx, 1);
        this.onPageTurn(this.pageView);
    }

    /**设置视图到指定索引页 */
    setPageIndex(index: number) {
        let contentPos = this._getContentPosByItemIdx(index)
        this._content.setPosition(contentPos)
        this.scrollToPage(index, 0);
        this.onPageTurn(this.pageView);
    }

    /**滑动视图到指定索引页 */
    scrollToPage(index: number, duration: number = 1) {
        this.pageView.scrollToPage(index, duration);
    }

    /**当前视图索引 */
    getCurrentPageIndex() {
        return this.pageView.getCurrentPageIndex();
    }

    /**获取页面 */
    getPages() {
        return this.pageView.getPages();
    }

}